Estoy experimentando un comportamiento extraño al organizar una matriz de bytes [] de C# en C++.
Cuando se pasa el byte[] como argumento, obtengo los datos esperados en C++. (Ver ReportData)
Cuando el byte [] está envuelto en una estructura, obtengo valores extraños. (Ver ReportBuffer)
¿Qué está causando esta diferencia en el comportamiento y hay alguna forma de corregirlo, ya que necesito tener los datos envueltos en un caso de uso más complejo?
C# Código de llamada
public struct Buffer { public int DataLength; public byte[] Data; public Buffer(byte[] data) : this() { Data = data; DataLength = data.Length; } } internal class Program { [DllImport(@"C:\Users\lawsm\source\repos\MarshallingTest\Debug\Test.dll", CallingConvention = CallingConvention.Cdecl)] private static extern void ReportBuffer(Buffer buffer); [DllImport(@"C:\Users\lawsm\source\repos\MarshallingTest\Debug\Test.dll", CallingConvention = CallingConvention.Cdecl)] private static extern void ReportData(byte[] data, int dataCount); private static void Main(string[] args) { byte[] data = new byte[] {0, 1, 2, 3, 4, 5}; Buffer buffer = new Buffer(data); Console.WriteLine("Report Buffer"); ReportBuffer(buffer); Console.WriteLine("\n\nReport Data"); ReportData(data, data.Length); Console.ReadKey(); } }Código DLL de C++
#include <cstdint> #include <iostream> struct Buffer { public: int DataLength; uint8_t* Data; }; extern "C" { _declspec(dllexport) void ReportBuffer(const Buffer& buffer) { for (int i = 0; i < buffer.DataLength; i++) { std::cout << (int)buffer.Data[i] << std::endl; } } _declspec(dllexport) void ReportData(uint8_t* data, int dataLength) { for (int i = 0; i < dataLength; i++) { std::cout << (int)data[i] << std::endl; } } }Salida de consola
Report Buffer 1 0 128 0 1 0 Report Data 0 1 2 3 4 5Descubrí una solución cambiando la matriz byte[] a un IntPtr, asignando el espacio y copiando los datos.
[StructLayout(LayoutKind.Sequential)] public struct Buffer { public int DataLength; public IntPtr Data; public Buffer(byte[] data) : this() { Data = Marshal.AllocHGlobal(data.Length); Marshal.Copy(data, 0, Data, data.Length); DataLength = data.Length; } } [DllImport("Buffer.dll", CallingConvention = CallingConvention.Cdecl)] private static extern void ReportBuffer(Buffer buffer);El código C++ sigue siendo el mismo:
struct Buffer { public: int DataLength; uint8_t* Data; }; extern "C" { _declspec(dllexport) void ReportBuffer(const Buffer& buffer) { std::cout << buffer.DataLength << std::endl; for (int i = 0; i < buffer.DataLength; i++) { std::cout << (int)buffer.Data[i] << std::endl; } } }